/************************************************************************
* tokenize.c
* Copyright (C) Lisa Milne 2013 <lisa@ltmnet.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
************************************************************************/

#include "dish.h"
#include "env.h"

static char** tok_append(char** toks, char* str)
{
	char buff[CFG_INPUT_BUFFER];
	char rbuff[CFG_INPUT_BUFFER];
	char* r;
	int i;
	int o = 0;
	int ro;
	int b;
	int l = strlen(str);

	for (i=0; i<l; i++) {
		/* environment variables */
		if (str[i] == '$') {
			if (i && str[i-1] == '\\') {
				o--;
				buff[o++] = str[i];
				continue;
			}
			i++;
			ro = 0;
			b = 0;
			if (str[i] == '{') {
				b = 1;
				i++;
			}
			for (; str[i]; i++) {
				if (str[i] == ' ' || (b && str[i] == '}'))
					break;
				rbuff[ro++] = str[i];
			}
			if (!ro)
				continue;
			rbuff[ro] = 0;
			r = env_get(rbuff);
			if (!r)
				continue;
			for (ro=0; r[ro]; ro++) {
				buff[o++] = r[ro];
			}
		/* backtick command substitution */
		}else if (str[i] == '`') {
			i++;
			ro = 0;
			for (; str[i]; i++) {
				if (str[i] == '`')
					break;
				rbuff[ro++] = str[i];
			}
			rbuff[ro] = 0;
			parse_line_buff(rbuff,STDIN_FILENO,rbuff,CFG_INPUT_BUFFER,STDERR_FILENO);
			for (ro=0; rbuff[ro]; ro++) {
				buff[o++] = rbuff[ro];
			}
			if (o && buff[o-1] == '\n')
				o--;
		}else{
			buff[o++] = str[i];
		}
	}

	buff[o] = 0;

	return clist_append(toks,buff,NULL);
}

/* tokenize a command */
char** tokenize(char* str, int *count)
{
	char** toks;
	char s = 0;
	int o = 0;
	int ws = 0;
	char buff[CFG_INPUT_BUFFER];

	toks = clist_gen(NULL);

	while (*str) {
		if (s && s == *str) {
			if (o && buff[o-1] == '\\') {
				buff[o-1] = s;
			}else{
				s = 0;
			}
			if (*str == '`')
				buff[o++] = *str;
		}else if (!s && !o && (*str == '"' || *str == '\'' || *str == '`')) {
			if (*str == '`')
				buff[o++] = *str;
			s = *str;
			ws = 1;
		}else if (!s && *str == ' ') {
			if (!o && !ws) {
				str++;
				continue;
			}
			buff[o] = 0;
			toks = tok_append(toks,buff);
			o = 0;
		}else if (!s && (*str == '|' || *str == '>' || *str == '<' || *str == ';')) {
			if (o) {
				buff[o] = 0;
				toks = tok_append(toks,buff);
				o = 0;
			}
			buff[0] = *str;
			if (*str == '>' && *(str+1) == '>') {
				buff[1] = '>';
				buff[2] = 0;
				str++;
			}else if (*str == '|' && *(str+1) == '|') {
				buff[1] = '|';
				buff[2] = 0;
				str++;
			}else{
				buff[1] = 0;
			}
			toks = tok_append(toks,buff);
		}else{
			buff[o++] = *str;
		}
		str++;
	}

	buff[o] = 0;
	if (o)
		toks = tok_append(toks,buff);

	*count = clist_count(toks);
	return toks;
}

/* find the last token in a string */
char* tok_last(char* str)
{
	char* t = strrchr(str,' ');
	if (!t)
		return str;

	return t+1;
}
